// 函数式编程

#include <iostream>
#include <vector>
#include <algorithm>

//目前C++中的纯函数编程不常见但用类似与map+lambda的轻度使用方式替换if else switch等可读性要好得多

/*
lambda表达式和普通函数都能访问外部的全局变量但lambda表达式相比起来可以访问局部变量而且有引用复制等多种访问方式
*/
using namespace std;

int n = 2;

auto funcs = [](int x) //每个lambda表达式都有独特的类型这个类型只有编译器知道 无法直接写出来 所以必须用auto
{ cout << "hello world " << x * n << endl; };

auto f3 = [](long x) -> int
{ return static_cast<int>(x); }; // lambda表达式一般不需要明确声明返回值类型，可以自动推导，但有时候需要明确指定返回类型，需要用类似rust的语法指定

class LambdaV
{
public:
    LambdaV() = default;

    LambdaV(LambdaV &lv)
    {
        this->num = lv.num;
        cout << "lambdav copy constructor called" << endl;
    }

    void print(const string &from)
    {
        cout << from << " Lambda num: " << num << endl;
    }

    void increment()
    {
        num++;
    }

private:
    int num = 1;
};

void nest_lambda()
{
    auto f2 = []()
    {
        cout << "lambda f2" << endl;
        int num = 0;
        auto f3 = []()
        {
        // cout << "lambda f3 " << num << endl; 报错 因为lambda声明为空[] 相当于一个普通的函数没有捕获功能
        };
        f3();
    };

    f2();
}

void lambda_as_param()
{
    vector<int> v = {1, 2, 3, 4, 5};
    //因为lambda表达式不是普通的变量所以尽量匿名使用lambda表达式这样也可以最小化它的影响范围让代码更安全
    //lambda表达式可以不声明返回类型可以自动推导也可以在尾部加上-> type明确指定返回值类型
    cout << *find_if(begin(v), end(v), [](int x)
                    { return x >= 5; })
         << endl;
    cout << *find_if(begin(v), end(v), [](int x) -> bool
                    { return x >= 5; })
         << endl;
}

//使用auto实现lambda参数的泛型化
auto f = [](const auto &x)
{
    return x + x;
};

//C++20的新泛型形式
auto f1 = []<typename T>(const T &x)
{
    static_assert(is_integral_v<T>);
    return x + x;
};

int main()
{
    /*
    使用lambda变量捕获要注意对于就地使用的lambda可以用[&] 而对于非本地调用
    声明周期较长的lambda 应慎用[&]捕获引用最好在[]里显式写出变量列表避免捕获不必要的变量
    确实需要长期持有外部变量为了避免变量失效可以考虑使用shared_ptr
    */
   class DemoLambda final 
   {
    private:
        int x = 0;
    public:
        auto print() {
            return [this]() //显式捕获this指针
            {
                cout << x << endl;
            };
        }
   };

    LambdaV lv;
    int num = 0;

    auto func1 = [=]()//按值捕获
    {
       //num++ x只读不允许修改
        auto ll = const_cast<LambdaV *>(&lv);
        ll->increment();
        ll->print("func1");
    };

    auto func2 = [&]()//按引用捕获
    {
        num++;
        lv.print("func2");
    };

    auto func3 = [=, &lv, &num]() //lv和x按引用 其它按值
    {
        num++;
        lv.print("func3");
    };

    auto func4 = [=]() mutable { // mutable表示可以修改按值捕获的num的值 修改的只是变量的内部拷贝不影响外部变量的原值
        num++;
    };

    func1();
    func2();
    func3();
    cout << "before func4 " << num << endl;
    func4();
    cout << "after func4 " << num << endl;

    nest_lambda();

    auto func = lambda_as_param;
    func();

    cout << f(1) << endl;
    cout << f(2.0) << endl;

    cout << f1(1) << endl;
    // cout << f1(2.0) << endl;  assert编译不过
}